# -*- coding:utf-8 -*-

import time
import urllib
import urllib2
import md5

# try to use web2py md5_hash
try:
    from gluon.utils import md5_hash
except ImportError:
    import md5 as md5_hash

# try to use simplejson first, otherwise fallback to XML
try:
    import simplejson
    RESPONSE_FORMAT = 'json'
except ImportError:
    try:
        from django.utils import simplejson
        RESPONSE_FORMAT = 'json'
    except ImportError:
        from xml.dom import minidom
        RESPONSE_FORMAT = 'xml'

from xml.dom import minidom
#from xml.etree import ElementTree
import xml.etree.ElementTree as ET
#RESPONSE_FORMAT = 'xml'

# support Google App Engine.
try:
    from google.appengine.api import urlfetch

    def urlread(url, data=None):
        if data is not None:
            headers = {'Content-type': "application/x-www-form-urlencoded"}
            method = urlfetch.POST
        else:
            headers = {}
            method = urlfetch.GET

        result = urlfetch.fetch(url, method=method,
                                payload=data, headers = headers)

        if result.status_code == 200:
            return result.content
        else:
            raise urllib2.URLError("fetch error url=%s, code=%d" % (url, result.status_code))
        
except ImportError:
    def urlread(url, data=None):
        rsp = urllib2.urlopen(url, data=data)
        return rsp.read()
#def urlread(url, data=None):
#    rsp = urllib2.urlopen(url, data=data)
#    return rsp.read()

__all__ = ['Sip']
VERSION = '0.1'

ISOTIMEFORMAT= '%Y-%m-%d %X'

SIP_URL = 'http://sip.alisoft.com/sip/rest'
SIP_LOGIN_URL = 'http://sip.alisoft.com/sip/login'
SIP_SECURE_URL = None
MY_ALISOFT_URL = 'http://mall.alisoft.com/apps/shopwindow/showAppDetailAction!view.jspa?appID=16635'

# my config
APP_KEY = '16635'
app_key = APP_KEY
appId = APP_KEY

CERT_CODE = '5894b000a0bf11dd8d3cfee3c21c434f'
cert_code = CERT_CODE

validate_user_keys_list = 'sip_apiname', 'sip_appkey', 'sip_timestamp', 'userId', 'appId', 'appInstanceId', 'token', 'sip_format',# 'sip_sessionid', 'v', 'fields','format'
login_keys_list = 'sip_apiname', 'sip_appkey', 'sip_sessionid', 'sip_redirecturl'

req_keys_list = {
    'alisoft':['app_instance_id', 'token', 'user_id', 'app_id', 'target'],
    'login': ['isp_username'],
    }

NAMESPACES = []

SIPMETHODS = {
    # TaoBao
    'taobao': {
        # 产品API
        'products':{
            # 搜索产品信息
            'search':[
                {'apiType': 1},
                ('fields', list, []),
                ('q', str, ['optional']), # 搜索的关键词(q,cid和props必须至少传一个)
                ('cid', str, ['optional']),
                ('props', str, ['optional']), # 属性、属性值的组合，格式：pid:vid;pid:vid
                ('page_size', int, ['optional']),
                ('page_on', int, ['optional']),
            ],
            # 获取一个产品的信息
            'get':[
                {'apiType': 1},
                ('fields', list, []),
                ('cid', str, ['optional']),
                ('props', str, ['optional']),
                ('product_id', str, ['optional']),
            ],
        },
        # 店铺API
        'shop':{
            # 获取卖家店铺基本信息
            'get':[
                {'apiType': 3},
                ('fields', list, []),
                ('nick', str, []),
                ('sip_sessionid', str, ['optional']),
            ],
#            # 更新店铺的标题、公告及介绍
#            'update':[
        },
        # 交易API
        'trades':{
            'bought':{
                # 搜索当前会话用户做为买家达成的交易记录。不支持历史交易数据。
                'get':[
                    {'apiType': 2},
                    ('sip_sessionid', str, []),
                    ('fields', list, []),
                    ('start_created', str, ['optional']),
                    ('page_no', int, ['optional']),
                    ('page_size', int, ['optional']),
                    ('title', str, ['optional']),
                    ('status', str, ['optional']),
                    ('end_created', str, ['optional']),
                ],
            },
            'sold':{
                # 搜索当前会话用户（做为卖家）已卖出的交易数据。不支持历史交易数据。
                'get':[
                    {'apiType': 2},
                    ('sip_sessionid', str, []),
                    ('fields', list, []),
                    ('start_created', str, ['optional']),
                    ('page_no', int, ['optional']),
                    ('page_size', int, ['optional']),
                    ('title', str, ['optional']),
                    ('status', str, ['optional']),
                    ('end_created', str, ['optional']),
                ],
            },
            # 搜索交易公开信息
            'get':[
                {'apiType': 1},
                ('iid', str, []),
                ('fields', str, []),
                ('seller_nick', str, []),
                ('page_no', int, []),
                ('page_size', int, []),
            ],
        },
        'trade':{
            # 获取单条交易信息，包含支付宝交易号、实付金额及邮费
            'get':[
                {'apiType': 2},
                ('sip_sessionid', str, []),
                ('fields', list, []), # seller_nick, buyer_nick, title, type, created, sid, buyer_message, tid, seller_rate, buyer_rate, status, payment, alipay_no, pay_time, end_time, out_sid, modified, buyer_obtain_point_fee, buyer_memo, seller_memo, point_fee, real_point_fee, total_fee, orders
                ('tid', str, []),
            ],
        },
        'orders':{
            # 查询某商品的出价记录
            'get':[
                {'apiType': 1},
                ('fields', list, []),
                ('iid', str, []),
                ('seller_nick', str, ['optional']),
                ('page_on', int, ['optional']),
                ('page_size', int, ['optional']),
            ],
        },
        # 类目属性API
        'itemcats':{
        },
        # 评价API
        'traderate':{
        },
        # 商品API
        'items': {
            # 搜索商品信息。支持分页和排序。目前该接口得到的数据和真实的商品数据会有１０分钟左右的延迟。
            'get': [
                {'apiType': 1},
                ('fields', list, [('default', ['iid'])]),
                ('q', str, ['optional']),
                ('nicks', list, ['optional']),
                ('cid', str, ['optional']),
                ('start_price', int, ['optional']),
                ('end_price', int, ['optional']),
                ('page_no', int, ['optional']),
                ('page_size', int, ['optional']),
                ('order_by', str, ['optional']),
                ('props', str, ['optional']),
                ('product_id', str, ['optional']),
                ('ww_status', bool, ['optional']),
                ('post_free', bool, ['optional']),
#                ('location.city', str, ['optional']),
                {'location': [
                    ('state', str, ['optional']),
                    ('city', str, ['optional']),
                    ],
                },
            ],
            'instock': {
                # 搜索当前会话用户（必须为卖家）的库存商品。支持分页。
                'get': [
                    {'apiType': 2},
                    ('sip_sessionid', str, []),
                    ('fields', list, [('default', ['iid'])]),
                    ('q', str, ['optional']),
                    ('page_no', int, ['optional']),
                    ('page_size', int, ['optional']),
                    ('banner', str, ['optional']),
                    ('order_by', str, ['optional']),
                ],
            },
            'onsale': {
                # 搜索当前会话用户（必须为卖家）的库存商品。支持分页。
                'get': [
                    {'apiType': 2},
                    ('sip_sessionid', str, []),
                    ('fields', list, [('default', ['iid'])]),
                    ('q', str, ['optional']),
                    ('page_no', int, ['optional']),
                    ('page_size', int, ['optional']),
                    ('banner', str, ['optional']),
                    ('order_by', str, ['optional']),
                ],
            },
        },
        'item':{
            # 得到单个商品信息。
            'get': [
                {'apiType': 3},
                ('iid', str, []),
                ('nick', str, []),
                ('fields', list, [('default', ['iid'])]),
                ('sip_sessionid', str, ['optional']),
            ],
            # 更新商品信息。目前暂不支持对二手宝贝进行更新。
            'update': [
                {'apiType': 2},
                ('sip_sessionid', str, []),
                ('iid', str, []),
                ('approve_status', str, ['optional']),
                ('cid', str, ['optional']),
                ('num', int, ['optional']),
                ('price', str, ['optional']),
                ('title', str, ['optional']),
                ('desc', str, ['optional']),
                {'location':[
                    ('state', str, ['optional']),
                    ('city', str, ['optional']),
                    ],
                },
                ('valid_thru', str, ['optional']),
                ('has_invoice', bool, ['optional']),
                ('has_warranty', bool, ['optional']),
                ('auto_repost', bool, ['optional']),
                ('has_showcase', bool, ['optional']),
                ('post_fee', str, ['optional']),
                ('express_fee', str, ['optional']),
                ('ems_fee', str, ['optional']),
                ('list_time', str, ['optional']),
                ('freight_payer', str, ['optional']),
                ('seller_cids', str, ['optional']), # 店铺类目列表.这里只做添加操作，不会覆盖原有的分类.
                ('has_discount', str, ['optional']),
                ('increment', bool, ['optional']),
                ('image', str, ['optional']),
                ('auction_point', str, ['optional']),
                ('property_alias', str, ['optional']),
                ('sku_ids', str, ['optional']),
                ('sku_properties', str, ['optional']),
                ('sku_quantities', str, ['optional']),
                ('sku_prices', str, ['optional']),
                ('sku_outer_ids', str, ['optional']),
                ('postage_id', str, ['optional']),
                ('props', str, ['optional']),
                ('stuff_status', str, ['optional']),
                ('lang', str, ['optional']),
            ],
        },
        # 物流API
        'shippings':{
        },
        # 用户API
        'user':{
            # 得到单个用户资料。
            'get':[
                {'apiType': 3},
                ('fields', list, []),
                ('nick', str, []),
                ('sip_sessionid', str, ['optional']),
            ],
        },
        'users': {
            # 批量得到用户公开资料
            'get': [
                {'apiType': 1},
                ('nicks', list, []),
                ('fields', list, [('default', ['nick', 'sex', 'buyer_credit', 'seller_credit'])]),
            ],
        },
    },
    # AliSoft
    'alisoft': {
        # 用户类接口
        # 验证用户身份，确保用户已经登录软件互联平台，并且是该应用的有效使用用户，一般从阿里软件互联平台跳转到ISV应用的身份验证过程中需要使用到。
        'validateUser': [
            {'apiType': 1},
            ('appId', str, []),
            ('appInstanceId', str, []),
            ('userId', str, []),
            ('token', str, []),
        ],
        # 验证某个用户是否某个订阅实例的有效用户。
        'validateAppUser': [
            {'apiType': 1},
            ('appId', str, []),
            ('appInstanceId', str, []),
            ('userId', str, []),
        ],
        # 验证群软件用户身份，确保用户已经登录软件互联平台，并且是该订购所在群的有效用户，一般从群服务tab页跳转到ISV应用的身份验证过程中需要使用到。
        'validateTribeUser': [
            {'apiType': 1},
            ('appId', str, []),
            ('appInstanceId', str, []),
            ('userId', str, []),
            ('token', str, []),
        ],
        'udb':{
            # 根据阿里巴巴中文站（或淘宝）帐号，获取用户在软件互联平台的用户ID。
            'getUserId': [
                {'apiType': 1},
                ('appId', str, []),
                ('domainid', str, []),
                ('loginid', str, []),
            ],
            # 根据软件互联平台的用户ID，获取用户的阿里巴巴中文站（或淘宝）帐号。
            'getDomainLoginId': [
                {'apiType': 1},
                ('appId', str, []),
                ('domainid', str, ['default','3']),
#                ('domainid', str, []),
                ('userid', str, []),
            ],
        },
        # 订购类接口
        # 获取某个用户订购的应用的用户使用列表。
        'getUsingUser': [
            {'apiType': 1},
            ('appId', str, []),
            ('appInstanceId', str, []),
        ],
        # Isv查询订阅记录的功能。
        'getSubscCtrl': [
            {'apiType': 1},
            ('appId', str, []),
            ('appInstanceId', str, []),
        ],
        # 旺旺类接口
        'im':{
            # 获取单个用户阿里旺旺在线的状态
            'userstatus2': [
                ('uid', str, []),
                ('site', str, []),
                ('v', int, [('default', 6)]),
            ],
            # 获取取阿里旺旺用户在线状态图标
            'online': [
                ('uid', str, []),
                ('site', str, []),
                ('s', str, []),
                ('v', int, [('default', 6)]),
            ],
            # 返回阿里旺旺用户洽谈JS脚本，在页面中嵌入此脚本，就能够自动调出旺旺的聊天窗口
            'msg': [
                ('uid', str, []),
                ('site', str, []),
                ('v', int, [('default', 6)]),
            ],
            # 获取多个用户ID阿里旺旺在线状态
            'mullidstatus': [
                ('beginnum', str, []),
                ('uids', str, []),
                ('v', int, [('default', 6)]),
            ],
#            'nofityMessage': [
#                ('user_Id', str, []),
#                ('app_Instance_Id', str, []),
#                ('message', str, []),
#            ],
        },
    },
}

class NameSpace(object):
    def __init__(self, name, client=None):
        self._name = name
        self._client = client
        self._parent = None
        self._children = []
        self._proxy = None

    def fullName(self):
        if self._parent is None:
            return self._name
        else:
            return '%s.%s' % (self._parent.fullName(), self._name)

    def title(self):
        if self._parent is None:
            return self._name.title()
        else:
            return '%s%s' % (self._parent.title(), self._name.title())
        
    def addChild(self, child):
        child._parent = self
        self._children.append(child)
        self.__dict__[child._name] = child

    def createProxy(self, client):
        if self._proxy is None:
            return NameSpace(self._name)
        else:
            return eval('%s(self._name, client)' % (self._proxy.__name__))
            
    def __str__(self):
        return self.fullName()

    def __repr__(self):
        return '%s' % (self.fullName())
        
    def __call__(self, method=None, args=None):
        if method is None:
            return self
        return self._client('%s.%s' % (self.fullName(), method), args)
    

def __generate_namespace(namespace, parent=None):
    current = NameSpace(namespace[0])

    if parent is not None:
        parent.addChild(current)
        
    methods = {}
    
    for child in namespace[1].items():
        if type(child[1]) == dict:
            #generate sub-namespaces
            __generate_namespace(child, current)
        elif type(child[1]) == list:
            #genrate namespace proxy
            params = ['self']
            body = ['args = {}']

            for parameter in child[1]:

                if isinstance(parameter, tuple):
                    param_name = parameter[0]
                    param_type = parameter[1]
                    param_options = parameter[2]
                    
                    method = child[0]
                    param = param_name

                    for option in param_options:
                        if isinstance(option, tuple) and option[0] == 'default':
                            if param_type == list:
                                param = '%s=None' % param_name
                                body.append('if %s is None: %s = %s' % (param_name, param_name, repr(option[1])))
                            else:
                                param = '%s=%s' % (param_name, repr(option[1]))

                    if 'optional' in param_options:
                        param = '%s=None' % param_name
                        body.append('if %s is not None: args[\'%s\'] = %s' % (param_name, param_name, param_name))
                    else:
                        body.append('args[\'%s\'] = %s' % (param_name, param_name))

                    params.append(param)
                
            body.insert(0, '"""method"""')
            body.insert(0, 'def %s(%s):' % (method, ', '.join(params)))
            body.append('return self(\'%s\', args)' % method)

            exec('\n    '.join(body))
            methods[method] = eval(method)

    if len(methods) > 0:
        proxy = type('%sProxy' % (current.title()), (NameSpace, ), methods)
        current._proxy = proxy
        globals()[proxy.__name__] = proxy
    
    return current

def __generate_namespaces():
    for namespace in SIPMETHODS.items():
        current = __generate_namespace(namespace)
        NAMESPACES.append(current)

__generate_namespaces()

class Proxy(object):
    """Represents a "namespace" of Facebook API calls."""

    def __init__(self, client, name):
        self._client = client
        self._name = name

    def __call__(self, method=None, args=None, add_session_args=True):
        # for Django templates
        if method is None:
            return self

        if add_session_args:
            self._client._add_session_args(args)

        return self._client('%s.%s' % (self._name, method), args)

class AuthProxy(NameSpace):
    """Special proxy for sip.auth."""

    def getSession(self):
        """Sip API call. See ... """
        args = {}        
        args['auth_token'] = self.auth_token
#        try:
#            args['auth_token'] = self.auth_token
#        except AttributeError:
#            raise RuntimeError('Client does not have auth_token set.')
        result = self._client('%s.getSession' % self._name, args)
        self._client._session_key = result['session_key']
        self._client._uid = result['uid']
        self._client._secret = result.get('secret')
        self._client._session_key_expires = result['expires']
        return result

    def createToken(self):
        """Sip API call. See ... """
        token = self._client('%s.createToken' % self._name)
        self._client._auth_token = token
        return token

class SIP(object):
    def __init__(self, app_key, cert_code, sip_url=None, auth_token=None, app_name=None, callback_path=None, internal=None, proxy=None,):
        self._app_key = app_key
        self._cert_code = cert_code
        self._session_key = None
        self._session_key_expires = None
        self.auth_token = auth_token
        self._secret = None
        self._uid = None
        self._page_id = None
        self._app_name = app_name
        self._callback_path = callback_path
        self._internal = internal
        self._proxy = proxy

        if sip_url is None:
            self._sip_url = SIP_URL
        else:
            self._sip_url = sip_url

        self._create_proxies()

        self.auth = AuthProxy(self, 'sip.auth') 
           
    def _create_proxy(self, namespace, parent=None):
        
        proxy = namespace.createProxy(self)
        if parent is None:
            self.__dict__[namespace._name] = proxy
        else:
            parent.addChild(proxy)
        
        for child in namespace._children:
            self._create_proxy(child, proxy)
            
    def _create_proxies(self):
        for namespace in NAMESPACES:
            self._create_proxy(namespace)
            
    def _sign(self, args):
        encrypt = md5.new()
        encrypt.update(self._cert_code)
        # Revise
        for k, v in sorted(args.items()):
            encrypt.update(k)
#            v = str(v)
            encrypt.update(v)
        return encrypt.hexdigest().upper()
        
    def _build_post_args(self, method, args=None):
        """adds to args parameters that are necessary for every call to the SIP."""
        if args is None:
            args = {}

        for arg in args.items():
            if type(arg[1]) == list:
                args[arg[0]] = ','.join(str(a) for a in arg[1])
            elif type(arg[1]) == unicode:
                args[arg[0]] = arg[1].encode("UTF-8")
            elif type(arg[1]) == bool:
                args[arg[0]] = str(arg[1]).lower()

        #add common args
        args['sip_appkey'] = self._app_key #ok
        args['sip_apiname'] = method #ok
        args['v'] = '1.0' #ok
        args['format'] = RESPONSE_FORMAT #ok
        args['sip_timestamp'] = self._get_timestamp() #ok
        args['sip_sign'] = self._sign(args) #ok
        
        return args

    def _add_session_args(self, args=None):
        """Adds 'session_key' and 'call_id' to args, which are used for API calls that need sessions."""
        if args is None:
            args = {}
        
        # me add!
        if not self._session_key:
            return args
            #some calls don't need a session anymore. this might be better done in the markup
            #raise RuntimeError('Session key not set. Make sure auth.getSession has been called.')
        
        args['session_key'] = self._session_key
        args['call_id'] = str(int(time.time() * 1000))
        
        return args

    def _parse_rsp(self, rsp, method, format=None):
        if not format:
            format = RESPONSE_FORMAT

        if format == 'json':
            result = simplejson.loads(rsp)
        elif format == 'xml':
            dom = minidom.parseString(rsp)
            result = self._parse_rsp_item(dom)
            dom.unlink()

            if 'error_response' in result:
                self._check_error(result['error_response'])
            
            # me add! ???
#            result = result[method[9:].replace('.', '_') + '_response']
            result = result
        else:
            raise RuntimeError('Invalid format specified.')
            
        return result

    def _parse_rsp_item(self, node):
        # me add ! G850 temp.py
        """Parses an XML response node from Facebook."""
        if node.nodeType == node.DOCUMENT_NODE and \
            node.childNodes[0].hasAttributes() and \
            node.childNodes[0].hasAttribute('list') and \
            node.childNodes[0].getAttribute('list') == "true":
            return {node.childNodes[0].nodeName: self._parse_rsp_list(node.childNodes[0])}
        elif node.nodeType == node.ELEMENT_NODE and \
            node.hasAttributes() and \
            node.hasAttribute('list') and \
            node.getAttribute('list')=="true":
            return self._parse_rsp_list(node)
        elif len(filter(lambda x: x.nodeType == x.ELEMENT_NODE, node.childNodes)) > 0:
            return self._parse_rsp_dict(node)
        else:
            return ''.join(node.data for node in node.childNodes if node.nodeType == node.TEXT_NODE)
     
    def _parse_rsp_dict(self, node):
        """Parses an XML dictionary response node from Facebook."""
        result = {}
        for item in filter(lambda x: x.nodeType == x.ELEMENT_NODE, node.childNodes):
           result[item.nodeName] = self._parse_rsp_item(item)
        if node.nodeType == node.ELEMENT_NODE and node.hasAttributes():
           if node.hasAttribute('id'):
               result['id'] = node.getAttribute('id')
        return result

    def _parse_rsp_list(self, node):
        """Parses an XML list response node from Facebook."""
        result = []
        for item in filter(lambda x: x.nodeType == x.ELEMENT_NODE, node.childNodes):
            result.append(self._parse_rsp_item(item))
        return result

    def _get_timestamp(self):
        stime = None
        if(time.timezone == 0):
            gmtimefix = 28800
            stime = time.gmtime(gmtimefix + time.time())
        else:
            stime = time.localtime()
        strtime = time.strftime(ISOTIMEFORMAT, stime)
        return strtime
    
    def _unicode_urlencode(self, params):
        if isinstance(params, dict):
            params = params.items()
        return urllib.urlencode([(k, isinstance(v, unicode) and v.encode('UTF-8') or v) for k, v in params])
    
    def __call__(self, method=None, args=None):
        post_data = self._unicode_urlencode(self._build_post_args(method, args))

        rsp = urlread(self._sip_url, post_data)

        return self._parse_rsp(rsp, method)
   
    # URL helpers
    def get_url(self, page, **args):
        """
        Returns one of the Facebook URLs (www.facebook.com/SOMEPAGE.php).
        Named arguments are passed as GET query string parameters.
    
        """
        return 'http://www.facebook.com/%s.php?%s' % (page, urllib.urlencode(args))
    
    
    def get_app_url(self, path=''):
        """
        Returns the URL for this app's canvas page, according to app_name.
    
        """
        return 'http://apps.facebook.com/%s/%s' % (self.app_name, path)
    
    
    def get_add_url(self, next=None):
        """
        Returns the URL that the user should be redirected to in order to add the application.
    
        """
        args = {'api_key': self.api_key, 'v': '1.0'}
    
        if next is not None:
            args['next'] = next
    
        return self.get_url('install', **args)
    
    
    def get_authorize_url(self, next=None, next_cancel=None):
        """
        Returns the URL that the user should be redirected to in order to
        authorize certain actions for application.
    
        """
        args = {'api_key': self.api_key, 'v': '1.0'}
    
        if next is not None:
            args['next'] = next
    
        if next_cancel is not None:
            args['next_cancel'] = next_cancel
    
        return self.get_url('authorize', **args)
    
    
    def get_login_url(self, next=None, popup=False, canvas=True):
        """
        Returns the URL that the user should be redirected to in order to login.
    
        next -- the URL that Facebook should redirect to after login
    
        """
        args = {'api_key': self.api_key, 'v': '1.0'}
    
        if next is not None:
            args['next'] = next
    
        if canvas is True:
            args['canvas'] = 1
    
        if popup is True:
            args['popup'] = 1
    
        if self.auth_token is not None:
            args['auth_token'] = self.auth_token
    
        return self.get_url('login', **args)
    
    
    def login(self, popup=False):
        """Open a web browser telling the user to login to Facebook."""
        import webbrowser
        webbrowser.open(self.get_login_url(popup=popup))
    
    
    def get_ext_perm_url(self, ext_perm, next=None, popup=False):
        """
        Returns the URL that the user should be redirected to in order to grant an extended permission.
    
        ext_perm -- the name of the extended permission to request
        next     -- the URL that Facebook should redirect to after login
    
        """
        args = {'ext_perm': ext_perm, 'api_key': self.api_key, 'v': '1.0'}
    
        if next is not None:
            args['next'] = next
    
        if popup is True:
            args['popup'] = 1
    
        return self.get_url('authorize', **args)
    
    
    def request_extended_permission(self, ext_perm, popup=False):
        """Open a web browser telling the user to grant an extended permission."""
        import webbrowser
        webbrowser.open(self.get_ext_perm_url(ext_perm, popup=popup))
    

def fetch(url):
    try:
        from google.appengine.api.urlfetch import fetch
        return fetch(url).content
    except:
        import urllib2
        return urllib2.urlopen(url).read()

#def getText(nodelist):
#    rc = ""
#    for node in nodelist.childNodes:
#        if node.nodeType == node.TEXT_NODE:
#            rc = rc + node.data
#    return rc
#
#def getTagText(root, tag):
#    node = root.getElementsByTagName(tag)[0]
#    rc = ""
#    for node in node.childNodes:
#        if node.nodeType in ( node.TEXT_NODE, node.CDATA_SECTION_NODE):
#            rc = rc + node.data
#    return rc

class SipApi(object):
    """ Provides access to the Sip API. """

    iso_time_format = ISOTIMEFORMAT
    sip_appkey = app_key

    def __init__(self):
        pass

    def now_time(self):
        """ get now time. """
        stime = None
        if(time.timezone == 0):
            gmtimefix = 28800
            stime = time.gmtime(gmtimefix + time.time())
        else:
            stime = time.localtime()
        strtime = time.strftime(self.iso_time_format, stime)
        return strtime

    def db_config_select(self,name):
        my_taobao_config = db(db.config.name == name).select()
        my_taobao_config = my_taobao_config[0]
        return my_taobao_config

    def sip_dict_all(self,vars):
        """ Create my all dict. """
        redirect_url = HOST + '/' + request.application + '/' + request.controller + '/' + request.function# + '?' + request.env['query_string']
        sip_dict = {}
#        sip_dict['sip_apiname'] = 'alisoft.validateAppUser'
        sip_dict['sip_apiname'] = 'taobao.trades.bought.get'
#        sip_dict['sip_apiname'] = 'alisoft.validateUser'
        sip_dict['sip_timestamp'] = self.now_time()
        sip_dict['sip_appkey'] = self.sip_appkey
        sip_dict['sip_format'] = 'json'
        sip_dict['v'] = '1.0'
        sip_dict['sip_sessionid'] = response.session_id
        sip_dict['sip_redirecturl'] = redirect_url
#        sip_dict['nicks'] = 'tel800810'
        sip_dict['domainid'] = 3
        sip_dict['fields'] = 'title' #'id,nick,created,location.city'
        sip_dict.update(vars)
        try:
            sip_dict['userid'] = sip_dict['userId']
        except:
            pass
        return sip_dict

    def sip_sign(self,list,dict):
        """ Create sign. """
        temp_dict = dict
        cert_code = cert_code
        keys_list = []
        for i in list:
            keys_list.append(i)
        keys_list.sort()
        sip_sign = ''
        for i in keys_list:
            sip_sign += i
            sip_sign += str(temp_dict[i])
        sip_sign = cert_code + sip_sign
        sip_sign = md5_hash(sip_sign)
        return sip_sign

    def sip_url(self,list,sip_dict):
        """ Create sip url only. """
        import copy
        url = ''
        temp_dict = copy.deepcopy(sip_dict)
        temp_dict['sip_timestamp'] = urllib.quote_plus(temp_dict['sip_timestamp'])
        for i in list:
            url += '%s=%s&' % (i, str(temp_dict[i]))
        return url

    def get_url(self,keys_list,sip_dict,URL=SIP_URL,sip_sign=True):
        """ Get my url. """
        sip_url = self.sip_url(keys_list, sip_dict)
        sip_url = URL + '?' + sip_url
        if sip_sign:
            sip_sign = self.sip_sign(keys_list, sip_dict)
            sip_url = sip_url + 'sip_sign=' + sip_sign
        return sip_url


taobao_api = SipApi()
sip = SIP(app_key, cert_code)

if __name__ == '__main__':
#    sip.login()
    print sip.__dict__
    sip.alisoft.validateUser(appId='16635', appInstanceId='ecf39007-9e3f-4546-92fd-6369a166b9fb',userId='4083559',token='92C82C9DF20EC21403D188993F29621DA5AEA773F85F74877CDC9A4E534C28F1EC0766810ADFB5053987A29774487421')
#    sip.taobao.items.get(fields=['iid', 'title', 'nick'], q='nike', sip_sessionid='sip_sessionid_temp')
#    sip.taobao.items.instock.get(fields=['iid', 'title', 'nick'], q='nike')

